package ntd.util.frame.javacv.action;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.cron.CronUtil;
import cn.hutool.cron.task.Task;
import cn.hutool.db.Db;
import cn.hutool.db.Entity;
import cn.hutool.log.StaticLog;
import lombok.SneakyThrows;
import ntd.action.ActionAbs;
import ntd.action.bo.ActionInBo;
import ntd.action.bo.ActionInfo;
import ntd.action.bo.ActionOutBo;
import ntd.tool.ToolCron;
import ntd.util.UtilCatch;
import ntd.util.UtilRun;
import ntd.util.config.common.bo.RequestInfo;
import ntd.util.config.common.exception.ComException;
import ntd.util.frame.data.factory.FactoryData;
import ntd.util.frame.javacv.ComVisionApi;
import ntd.util.frame.javacv.action.bean.VisionModelDo;
import ntd.util.frame.javacv.action.bo.ImgAnalysisInBo;
import ntd.util.frame.javacv.bo.CameraBO;
import ntd.util.frame.javacv.config.AiConfig;
import ntd.util.frame.javacv.remote.AiVisionRemote;
import ntd.util.frame.javacv.tool.ToolFtpSync;
import com.c.Constant;
import ntd.util.frame.javacv.vlc.FactoryVlc;
import ntd.util.util.ToolDuration;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.CountDownLatch;

/**
 * 数据质量
 */
public class ActionImgAnalysis extends ActionAbs {

    List<ImgAnalysisInBo> imgAnalysisInBos = new ArrayList<>();

    private static int aiRemoteIndex = 0;

    @Override
    public ActionInfo info() {
        return new ActionInfo("机器视觉图片分析", "ai-vision-img-analysis", new ActionImgAnalysis());
    }

    public ActionImgAnalysis() {
//        this.init();
//        UtilRun.onlyOne("ai-vision-img-analysis-init", this::init);
    }

    @Override
    public ActionOutBo handle() {
        UtilRun.onlyOne("ai-vision-img-analysis-init", this::init);

        ImgAnalysisInBo imgAnalysisInBo = actionInBo.getData().toBean(ImgAnalysisInBo.class);
        // 验证入参
        verify(imgAnalysisInBo);
        ToolDuration.duration(() -> {
            // 加入队列
            imgAnalysisInBos.add(imgAnalysisInBo);
        }, StrUtil.format("[{}]加入分析", imgAnalysisInBo.getCameraCode()));
        return new ActionOutBo("已加入分析");
    }

    public void init() {
        CronUtil.schedule("*/30 * * * * *", (Task) () -> {
            // 按模型分组
            Db db = Db.use(FactoryData.dataSource("272ab1b9c5cc4ea2b76302238247284c"));
            List<AiVisionRemote> aiVisionRemotes = ComVisionApi.analysisRemoteList();
            try {
                List<ImgAnalysisInBo> imgAnalysisInBosTemp = this.imgAnalysisInBos;
                this.imgAnalysisInBos = new ArrayList<>();

                List<VisionModelDo> aiVisionModelAll = db.findAll(new Entity("ai_vision_model"), VisionModelDo.class);

                for (VisionModelDo visionModelDo : aiVisionModelAll) {
                    Collection<ImgAnalysisInBo> modeCameras = CollectionUtil.filterNew(imgAnalysisInBosTemp, imgAnalysisInBo ->
                            imgAnalysisInBo.getVisionModelCodes().contains(visionModelDo.getCode()));
                    if (CollectionUtil.isNotEmpty(modeCameras)) {
                        String currentDateDay = DateUtil.format(DateUtil.date(), Constant.DATE_FORMAT_WLW_FOUR);

                        String path = StrUtil.format("{}-{}-{}", visionModelDo.getCode(), currentDateDay, IdUtil.simpleUUID());
                        String remoteFtpPath = StrUtil.format("{}{}", AiConfig.AI_SERVER_DATA_BASE_PATH, path);

                        AiVisionRemote aiVisionRemote = aiVisionRemotes.get(aiRemoteIndex++ % aiVisionRemotes.size());
                        ToolFtpSync toolFtpSync = aiVisionRemote.getFtpSync();

                        CountDownLatch countDownLatchUp = ThreadUtil.newCountDownLatch(modeCameras.size());
                        for (ImgAnalysisInBo modeCamera : modeCameras) {
                            ThreadUtil.execAsync(() -> UtilCatch.tryCatchNoRes(() -> {
                                String imgName = StrUtil.format("{}-{}-{}-{}-image.jpg", modeCamera.getMn(), modeCamera.getCameraCode(), modeCamera.getDatetime(),
                                        visionModelDo.getCode());
                                toolFtpSync.upload(remoteFtpPath, imgName, modeCamera.getImg());
                            }, countDownLatchUp::countDown));
                        }
                        UtilCatch.tryCatchNoRes(countDownLatchUp::await);

                        // 调用分析
                        aiVisionRemote.analyse(remoteFtpPath, visionModelDo.getCode(),visionModelDo.getPortNormal());
                    }
                }
                
            } catch (SQLException e) {
                StaticLog.error(e, "[AI][图片分析][{}]失败...");
            }
        });
        ToolCron.initTask();
    }

    private void verify(ImgAnalysisInBo imgAnalysisInBo) {
        String cameraCode = imgAnalysisInBo.getCameraCode();
        if (StrUtil.isBlank(cameraCode)) {
            throw new ComException("监控设备编码为空");
        }
        if (ArrayUtil.isEmpty(imgAnalysisInBo.getImg())) {
            throw new ComException("{} - 图片不能为空", cameraCode);
        }
        if (CollectionUtil.isEmpty(imgAnalysisInBo.getVisionModelCodes())) {
            throw new ComException("{} - 分析模型不能为空", cameraCode);
        }
        // 判断重复
        ImgAnalysisInBo one = CollectionUtil.findOne(imgAnalysisInBos, item ->
                imgAnalysisInBo.getCameraCode().equals(item.getCameraCode()));
        if (ObjectUtil.isNotNull(one)) {
            throw new ComException("{} - 存在重复分析", cameraCode);
        }
    }

    public static void main(String[] args) {
        ActionInBo inBo = new ActionInBo();

        List<String> modelTypes = ListUtil.of("Person", "Water");

        CameraBO cameraBO = ComVisionApi.initCameraList().get(0);

        byte[] snapshotAboutBytes = FactoryVlc.getSnapshotAboutBytes(cameraBO.initRtspUrl());

        inBo.setData(Dict.parse(new ImgAnalysisInBo("18637363854", "6b36a34d5ea14c0c8d33bf0ddbd1fa01", snapshotAboutBytes, modelTypes)));

        new ActionImgAnalysis().execute(inBo);
    }
}
